package com.pointi.vasEngine;

import java.util.ArrayList;

import com.pointi.emoServerM.JDBC;
import com.pointi.emoTools.emoConfig;
import com.pointi.emoTools.ezData;
import com.pointi.emoTools.ezKMeans;
import com.pointi.emoTools.vasData;
import com.pointi.emoTools.vasResult;
import com.pointi.emoTools.vasUnit;

public class vasEngine
{
	//____________________________________________________________________________________________________
	// 000 // vasEngine

	private String callkey = "" ;
	private JDBC jdbc ;
	private emoConfig eCONF ;

	public vasEngine(String callkey, JDBC jdbc, emoConfig eCONF)
	{
		this.callkey = callkey ;
		this.jdbc = jdbc ;
		this.eCONF = eCONF ;
	}

	public void fnClustering(ArrayList<int[]> inIndex, ArrayList<double[]> feature)
	{
		ArrayList<ezData> ez_20ms = new ArrayList<ezData>() ;
		ArrayList<vasData> vd_20ms = new ArrayList<vasData>() ;
		ArrayList<vasUnit> vu_1s = new ArrayList<vasUnit>() ;
		
		if(feature.size() == 0)
		{
			for(int i=0; i<inIndex.size(); i++)
			{
				vasData vd = new vasData() ;
				vd.subtime(i) ;
				vd.cluster(0) ;
				vd_20ms.add(vd) ;
			}
		}
		else
		{
			this.fnKMeanCluster(feature, ez_20ms) ;	// [001]
			this.fnMergeNonvoice(inIndex, ez_20ms, vd_20ms) ; // [002]
		}
		this.fnDownSampling(vd_20ms, vu_1s) ; // [003]
		this.fnCreateVDB(vu_1s) ; // [004]
		this.fnLayeredFilter(vu_1s) ; // [005]
		this.fnCreateVSDB(vu_1s) ; // [006]
		this.fnCreateYDB(vu_1s) ; // [007]
	}

	//____________________________________________________________________________________________________
	// 001 // K-Means Clustering Algorithm

	private void fnKMeanCluster(ArrayList<double[]> inData, ArrayList<ezData> ez_20ms)
	{
		int K = eCONF.VE_CNT() ;
		int LOOPLIMIT = eCONF.VE_LIMIT() ;
		ezKMeans kmeans = new ezKMeans(K, LOOPLIMIT) ;
		kmeans.fnSeparateData(inData, ez_20ms) ;
	}

	//____________________________________________________________________________________________________
	// 002 // Merge Voice and Non-Voice Info.

	private void fnMergeNonvoice(ArrayList<int[]> inIndex, ArrayList<ezData> ez_20ms, ArrayList<vasData> vd_20ms)
	{
		int ez_idx = 0 ;
		int feature_depth = ez_20ms.get(0).depth() ;
		for(int i=0; i<inIndex.size(); i++)
		{
			int cluster = 0 ;
			int subtime = inIndex.get(i)[0] ;
			int isVoice = inIndex.get(i)[1] ;
			vasData tv = new vasData(feature_depth) ;
			tv.subtime(subtime) ;
			if(isVoice == 1)
			{
				cluster = ez_20ms.get(ez_idx).cluster() ;
				tv.features(ez_20ms.get(ez_idx).element()) ;
				ez_idx++ ;
			}
			tv.cluster(cluster) ;
			vd_20ms.add(tv) ;
		}
	}
	
	//____________________________________________________________________________________________________
	// 003 // Down Sampling to vasUnit // vasData(20msec) x 50ea = vasUnit(1sec)

	private void fnDownSampling(ArrayList<vasData> vd_20ms, ArrayList<vasUnit> vu_1s)
	{
		int subtime = 0 ;
		int dur = (int)Math.ceil(vd_20ms.size()) ;
		int pu_cnt = 0 ;
		vasUnit tu = new vasUnit() ;
		tu.fnInitialize() ;
		tu.callkey(Integer.valueOf(this.callkey)) ;
		for(int i=0; i<dur; i++)
		{
			pu_cnt++ ;
			switch(vd_20ms.get(i).cluster())
			{
				case vasData._CLUSTER_A : tu.voice1_add() ; break ;
				case vasData._CLUSTER_B : tu.voice2_add() ; break ;
				default : tu.nonvoice_add() ; break ;
			}
			if((pu_cnt == eCONF.VE_HZ()) || ((i+1) == dur))
			{
				pu_cnt = 0 ;
				subtime ++ ;
				tu.subtime(subtime) ;
				vu_1s.add(new vasUnit(tu.callkey(), tu.subtime(), tu.status(), tu.voice1_cnt(), tu.voice2_cnt(), tu.nonvoice_cnt())) ;
				tu.fnInitialize() ;
			}
		}
	}

	//____________________________________________________________________________________________________
	// 004 // t_engine_Vyyyymmdd // 2014.06.10

	private void fnCreateVDB(ArrayList<vasUnit> vu_1s)
	{
		System.out.println("[VE] INSERT V-Table") ;
		jdbc.fnInsertVoiceEngineV(vu_1s) ;
	}
	
	//____________________________________________________________________________________________________
	// 005 // Correction Filter // Layered Filter

	private void fnLayeredFilter(ArrayList<vasUnit> vu_1s)
	{
		System.out.println("[VE] Correction Filter") ;
		vasCorrectionFilter CF = new vasCorrectionFilter(eCONF) ;
		CF.fnLayeredFilter(vu_1s, CF.fnCalculateAverage(vu_1s)) ;
	}
	
	//____________________________________________________________________________________________________
	// 006 // t_engine_VSyyyymmdd

	private void fnCreateVSDB(ArrayList<vasUnit> vu_1s)
	{
		System.out.println("[VE] INSERT V'-Table") ;
		jdbc.fnInsertVoiceEngineVS(vu_1s) ;
	}

	//____________________________________________________________________________________________________
	// 007 // t_engine_Yyyyymmdd // 2014.06.12
	
	private void fnCreateYDB(ArrayList<vasUnit> vu_1s)
	{
		ArrayList<double []> voice = new ArrayList<double []>() ;
		ArrayList<ezData> ez_1s = new ArrayList<ezData>() ;
		ArrayList<int []> section = new ArrayList<int []>() ;
		ArrayList<int []> section_group = new ArrayList<int []>() ;
		ArrayList<vasResult> section_fixed = new ArrayList<vasResult>() ;

		System.out.println("[VE] 2nd-Clustering") ;
		this.fnSeparateNonvoice(vu_1s, voice, section) ; // [007][01]
		this.fnKMeanCluster(voice, ez_1s) ; // [001]
		this.fnReIndexingCluster(ez_1s) ; // [007][05]
		this.fnMergeNonvoice(section, ez_1s) ; // [007][02]
		
		System.out.println("[VE] Fix Speaker Section") ;
		this.fnCreateSectionGroup(section, section_group) ; // [007][03]
		
		System.out.println("[VE] INSERT YS-Table") ;
		this.fnInsertVoiceEngineYS(section_group) ;

		vasCorrectionFilter CF = new vasCorrectionFilter(eCONF) ;
		CF.fnSectionFixFilter(section_group, vu_1s) ;

		//// CREATE vasResult // 2104.06.11
		int subtime = 0 ;
		int status = 2 ;
		for (int i=0; i<section_group.size(); i++)
		{
			int sec = section_group.get(i)[0] ;
			int dur = section_group.get(i)[1] ;
			for (int j=0; j<dur; j++)
			{
				subtime++ ;
				section_fixed.add(new vasResult(Integer.valueOf(this.callkey), status, sec, subtime)) ;
			}
		}

		//// INSERT Y-Table // vasResult // 2014.06.10
		System.out.println("[VE] INSERT Y-Table") ;
		jdbc.fnInsertVoiceEngineY(section_fixed) ;

		//// UPDATE R-Table.side // 2014.06.10
		System.out.println("[VE] UPDATE R-Table | Side-Col") ;
		jdbc.fnUpdateEmotionSide(section_group, Integer.valueOf(this.callkey)) ;
	}
	//____________________________________________________________________________________________________
	// 007 // 01 // pop nonvoice
	private void fnSeparateNonvoice(ArrayList<vasUnit> vu_1s, ArrayList<double []> voice, ArrayList<int []> section)
	{
		int nv_cnt = 0 ;
		int subtime = 0 ;
		double [] vc = null ;
		int [] nvc = null ;
		for (int i=0; i<vu_1s.size(); i++)
		{
			subtime = (i + 1) ;
			nv_cnt = vu_1s.get(i).nonvoice_cnt() ; 
			nvc = new int [2] ;
			nvc[0] = subtime ;
			nvc[1] = -1 ;
			if (nv_cnt == 50)
			{
				nvc[1] = 0 ;
			}
			else
			{
				vc = new double [2] ;
				vc[0] = vu_1s.get(i).voice1_cnt() ;
				vc[1] = vu_1s.get(i).voice2_cnt() ;
				voice.add(vc) ;
			}
			section.add(nvc) ;
		}
	}
	//____________________________________________________________________________________________________
	// 007 // 02 // push nonvoice
	private void fnMergeNonvoice(ArrayList<int []> section, ArrayList<ezData> ez_1s) 
	{
		for (int i=0; i<section.size(); i++)
		{
			if (section.get(i)[1] == -1)
			{
				section.get(i)[1] = ez_1s.get(0).cluster() ;
				ez_1s.remove(0) ;
			}
		}
	}
	//____________________________________________________________________________________________________
	// 007 // 03 // section to section_group
	private void fnCreateSectionGroup(ArrayList<int[]> section, ArrayList<int []> section_group)
	{
		int ID = -1 ;
		int CNT = -1 ;
		for (int i=0; i<section.size(); i++)
		{
			if (ID == section.get(i)[1])
			{
				CNT++ ;
			}
			else
			{
				if (ID != -1) // SKIP Start Point
				{
					int [] new_group = {ID, CNT} ;
					section_group.add(new_group) ;
				}
				ID = section.get(i)[1] ;
				CNT = 1 ;
			}
		}
		int [] new_group = {ID, CNT} ;
		section_group.add(new_group) ;
	}
	//____________________________________________________________________________________________________
	// 007 // 04 // t_engine_YSyyyymmdd // non-fixed section data
	private void fnInsertVoiceEngineYS(ArrayList<int []> section_group)
	{
		ArrayList<vasResult> section_fixed = new ArrayList<vasResult>() ;
		this.fnUnGroupSection(section_group, section_fixed) ;
		jdbc.fnInsertVoiceEngineYS(section_fixed) ;
	}
	//____________________________________________________________________________________________________
	// 007 // 05 // UnGroup Section
	private void fnUnGroupSection(ArrayList<int []> section_group, ArrayList<vasResult> section_fixed)
	{
		//// CREATE vasResult // 2104.06.11
		int subtime = 0 ;
		int status = 2 ;
		for (int i=0; i<section_group.size(); i++)
		{
			int sec = section_group.get(i)[0] ;
			int dur = section_group.get(i)[1] ;
			for (int j=0; j<dur; j++)
			{
				subtime++ ;
				section_fixed.add(new vasResult(Integer.valueOf(this.callkey), status, sec, subtime)) ;
			}
		}
	}
	//____________________________________________________________________________________________________
	// 007 // 06 // Re-Indexing Cluster
	private void fnReIndexingCluster(ArrayList<ezData>ez_1s)
	{
		int c1_cnt = 0 ;
		int c2_cnt = 0 ;

		for (int i=0; i<ez_1s.size(); i++)
		{
			if (ez_1s.get(i).cluster() == 1) { c1_cnt++ ; }
			else { c2_cnt++ ; }
		}
		if (c1_cnt < c2_cnt)
		{
			/*/ RE-INDEXING (2014.06.27) /*/
			/** 비중이 높은 화자를 일단 상담원이라고 가정하고 무조건 1로 인덱싱 한다 **/
			for (int i=0; i<ez_1s.size(); i++)
			{
				if (ez_1s.get(i).cluster() == 1) { ez_1s.get(i).cluster(2) ; }
				else { ez_1s.get(i).cluster(1) ; }
			}
		}
	}

	//____________________________________________________________________________________________________
	// EOC
}
